pub mod engine;
pub mod types;
pub mod ttl;

use dashmap::DashMap;
use parking_lot::RwLock;
use std::sync::Arc;
use std::time::{SystemTime, UNIX_EPOCH};

pub use types::*;
pub use engine::*;
pub use ttl::*;

/// Storage engine implementation
#[derive(Debug)]
pub struct Storage {
    /// Main data storage
    data: DashMap<String, RedisValue>,
    /// TTL storage (key -> expiration timestamp)
    ttl: DashMap<String, u64>,
    /// Storage statistics
    stats: Arc<RwLock<StorageStats>>,
}

#[derive(Debug, Default)]
pub struct StorageStats {
    pub total_keys: usize,
    pub expired_keys: usize,
    pub memory_usage: usize,
    pub hits: usize,
    pub misses: usize,
}

impl Storage {
    /// Create a new storage instance
    pub fn new() -> Self {
        Self {
            data: DashMap::new(),
            ttl: DashMap::new(),
            stats: Arc::new(RwLock::new(StorageStats::default())),
        }
    }

    /// Get current timestamp in seconds
    fn current_timestamp() -> u64 {
        SystemTime::now()
            .duration_since(UNIX_EPOCH)
            .unwrap()
            .as_secs()
    }

    /// Check if a key has expired
    fn is_expired(&self, key: &str) -> bool {
        if let Some(expiry) = self.ttl.get(key) {
            *expiry < Self::current_timestamp()
        } else {
            false
        }
    }

    /// Remove expired key
    fn remove_if_expired(&self, key: &str) -> bool {
        if self.is_expired(key) {
            self.data.remove(key);
            self.ttl.remove(key);
            self.stats.write().expired_keys += 1;
            true
        } else {
            false
        }
    }
}

impl StorageEngine for Storage {
    fn get(&self, key: &str) -> Option<RedisValue> {
        if self.remove_if_expired(key) {
            self.stats.write().misses += 1;
            return None;
        }

        if let Some(value) = self.data.get(key) {
            self.stats.write().hits += 1;
            Some(value.clone())
        } else {
            self.stats.write().misses += 1;
            None
        }
    }

    fn set(&self, key: String, value: RedisValue, ttl: Option<u64>) -> bool {
        let old_exists = self.data.contains_key(&key);

        self.data.insert(key.clone(), value);

        if let Some(ttl_seconds) = ttl {
            let expiry = Self::current_timestamp() + ttl_seconds;
            self.ttl.insert(key, expiry);
        } else {
            self.ttl.remove(&key);
        }

        if !old_exists {
            self.stats.write().total_keys += 1;
        }

        true
    }

    fn del(&self, key: &str) -> bool {
        let had_key = self.data.remove(key).is_some();
        self.ttl.remove(key);

        if had_key {
            self.stats.write().total_keys -= 1;
        }

        had_key
    }

    fn exists(&self, key: &str) -> bool {
        if self.remove_if_expired(key) {
            false
        } else {
            self.data.contains_key(key)
        }
    }

    fn keys(&self, pattern: &str) -> Vec<String> {
        // Simple pattern matching (only supports * wildcard)
        let mut result = Vec::new();

        for entry in self.data.iter() {
            let key = entry.key();
            if !self.is_expired(key) && self.matches_pattern(key, pattern) {
                result.push(key.clone());
            }
        }

        result
    }

    fn r#type(&self, key: &str) -> Option<String> {
        if self.remove_if_expired(key) {
            return None;
        }

        self.data.get(key).map(|value| match value.value() {
            RedisValue::String(_) => "string".to_string(),
            RedisValue::List(_) => "list".to_string(),
            RedisValue::Set(_) => "set".to_string(),
            RedisValue::Hash(_) => "hash".to_string(),
            RedisValue::ZSet(_) => "zset".to_string(),
        })
    }

    fn ttl(&self, key: &str) -> Option<i64> {
        if self.remove_if_expired(key) {
            return Some(-2); // Key doesn't exist
        }

        if !self.data.contains_key(key) {
            return Some(-2); // Key doesn't exist
        }

        if let Some(expiry) = self.ttl.get(key) {
            let now = Self::current_timestamp();
            if *expiry > now {
                Some((*expiry - now) as i64)
            } else {
                Some(-2) // Expired
            }
        } else {
            Some(-1) // No expiration
        }
    }

    fn expire(&self, key: &str, seconds: u64) -> bool {
        if self.remove_if_expired(key) || !self.data.contains_key(key) {
            return false;
        }

        let expiry = Self::current_timestamp() + seconds;
        self.ttl.insert(key.to_string(), expiry);
        true
    }

    fn persist(&self, key: &str) -> bool {
        if self.remove_if_expired(key) || !self.data.contains_key(key) {
            return false;
        }

        self.ttl.remove(key).is_some()
    }
}

impl Storage {
    /// Simple pattern matching for KEYS command
    fn matches_pattern(&self, key: &str, pattern: &str) -> bool {
        if pattern == "*" {
            return true;
        }

        // Very basic glob pattern matching
        if pattern.contains('*') {
            let parts: Vec<&str> = pattern.split('*').collect();
            if parts.len() == 2 {
                let prefix = parts[0];
                let suffix = parts[1];
                return key.starts_with(prefix) && key.ends_with(suffix);
            }
        }

        key == pattern
    }

    /// Get storage statistics
    pub fn stats(&self) -> StorageStats {
        let stats = self.stats.read();
        StorageStats {
            total_keys: stats.total_keys,
            expired_keys: stats.expired_keys,
            memory_usage: stats.memory_usage,
            hits: stats.hits,
            misses: stats.misses,
        }
    }

    /// Flush all data
    pub fn flush_all(&self) {
        self.data.clear();
        self.ttl.clear();
        *self.stats.write() = StorageStats::default();
    }
}